home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 October: Mac OS SDK / Dev.CD Oct 00 SDK1.toast / Development Kits / Mac OS / MLTE SDK / TEtoMLTESample / CommonSources / TApplication.cp next >
Encoding:
Text File  |  1999-12-05  |  15.8 KB  |  535 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    MultiFinder-Aware Simple Application Framework
  6. #
  7. #    TApplication
  8. #
  9. #    TApplication.cp        -    C++ source
  10. #
  11. #    Copyright © 1989 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Versions:    
  15. #            1.20                    10/91
  16. #            1.10                     07/89
  17. #            1.00                     04/89
  18. #
  19. #    Components:
  20. #            TApplicationCommon.h    July 9, 1989
  21. #            TApplication.h            July 9, 1989
  22. #            TApplication.cp            July 9, 1989
  23. #            TApplication.r            July 9, 1989
  24. #            TDocument.h                July 9, 1989
  25. #
  26. #    TApplication is a rudimentary application framework
  27. #    for C++.
  28. #
  29. ------------------------------------------------------------------------------*/
  30.  
  31.  
  32. /*
  33. Segmentation strategy:
  34.  
  35.     This program has only one segment, since the issues
  36.     surrounding segmentation within a class's methods have
  37.     not been investigated yet. We DO unload the data
  38.     initialization segment at startup time, which frees up
  39.     some memory 
  40.  
  41. SetPort strategy:
  42.  
  43.     Toolbox routines do not change the current port. In
  44.     spite of this, in this program we use a strategy of
  45.     calling SetPort whenever we want to draw or make calls
  46.     which depend on the current port. This makes us less
  47.     vulnerable to bugs in other software which might alter
  48.     the current port (such as the bug (feature?) in many
  49.     desk accessories which change the port on OpenDeskAcc).
  50.     Hopefully, this also makes the routines from this
  51.     program more self-contained, since they don't depend on
  52.     the current port setting. 
  53.  
  54. Clipboard strategy:
  55.  
  56.     This program does not maintain a private scrap.
  57.     Whenever a cut, copy, or paste occurs, we import/export
  58.     from the public scrap to TextEdit's scrap right away,
  59.     using the TEToScrap and TEFromScrap routines. If we did
  60.     use a private scrap, the import/export would be in the
  61.     activate/deactivate event and suspend/resume event
  62.     routines. 
  63. */
  64.  
  65. // Mac Includes
  66. #include <Types.h>
  67. #include <Quickdraw.h>
  68. #include <Fonts.h>
  69. #include <Controls.h>
  70. #include <Windows.h>
  71. #include <Menus.h>
  72. #include <TextEdit.h>
  73. #include <Dialogs.h>
  74. #include <Devices.h>
  75. #include <Events.h> 
  76. #include <Scrap.h>
  77. #include <ToolUtils.h>
  78. #include <MacMemory.h>
  79. #include <SegLoad.h>
  80. #include <Files.h>
  81. #include <OSUtils.h>
  82. #include <Traps.h>
  83. #include <LowMem.h>
  84. #include <Processes.h>
  85. #include <TextUtils.h>
  86.  
  87. #include "TApplication.h"                    // use the local version. If you make changes
  88.                                             // that you've debugged and want other files
  89.                                             // to use, simple copy this header file into
  90.                                             // the C++ Includes folder (don't forget to
  91.                                             // copy the TApplication object library to the C++
  92.                                             // Libraries folder)!
  93.  
  94. // OSEvent is the event number of the suspend/resume and mouse-moved events sent
  95. // by MultiFinder. Once we determine that an event is an osEvent, we look at the
  96. // high byte of the message sent to determine which kind it is. To differentiate
  97. // suspend and resume events we check the resumeMask bit.
  98. const short kOsEvent = app4Evt;                // event used by MultiFinder
  99. const short kSuspendResumeMessage = 0x01;    // high byte of suspend/resume event message
  100. const short kClipConvertMask = 0x02;        // bit of message field clip conversion
  101. const short kResumeMask = 0x01;                // bit of message field for resume vs. suspend
  102. const short kMouseMovedMessage = 0xFA;        // high byte of mouse-moved event message
  103.  
  104.  
  105.  
  106. /***********************************************************************/
  107. //
  108. // TApplication class declarations
  109. //
  110. /***********************************************************************/
  111.  
  112. //-----------------------------------------------------------------------
  113. // TApplication::TApplication -     
  114. //
  115.     TApplication::TApplication( void )
  116.     {
  117.         SysEnvRec envRec;
  118.         long stkNeeded, heapSize;
  119.     
  120.         // initialize Mac Toolbox components
  121.             InitGraf (&qd.thePort);
  122.  
  123.             InitFonts();
  124.             InitWindows();
  125.             InitMenus();
  126.             TEInit();
  127.             InitDialogs(nil);
  128.             InitCursor();
  129.     
  130. #ifndef powerc
  131.         // Unload data segment: note that _DataInit must not be in Main!
  132.             UnloadSeg((ProcPtr) _DataInit);
  133. #endif
  134.  
  135.         // ignore the error returned from SysEnvirons; even if an error occurred,
  136.         // the SysEnvirons glue will fill in the SysEnvRec
  137.             ( void ) SysEnvirons( curSysEnvVers, &envRec );
  138.     
  139.         // Are we running on a 128K ROM machine or better???
  140.             if ( envRec.machineType < 0 )
  141.                 BigBadError( kErrStrings,eWrongMachine );        // if not, alert & quit
  142.     
  143.         // if we need more stack space, get it now
  144.             stkNeeded = StackNeeded();
  145.             if (stkNeeded > StackSpace())
  146.             {
  147.                 // new address is heap size + current stack - needed stack
  148.                     SetApplLimit((Ptr) ((long) GetApplLimit() - stkNeeded + StackSpace()));
  149.             }
  150.     
  151.         // Check for minimum heap size
  152.             heapSize = (long) GetApplLimit() - (long) ApplicationZone();
  153.             if ( heapSize < HeapNeeded())
  154.                 BigBadError( kErrStrings, eSmallSize );
  155.     
  156.         // expand the heap so new code segments load at the top
  157.             MaxApplZone();
  158.     
  159.         // allocate an empty document list
  160.             fDocList = new TDocumentList;
  161.     
  162.         // check to see if WaitNextEvent is implemented
  163.             fHaveWaitNextEvent = TrapAvailable( _WaitNextEvent, ToolTrap );
  164.     
  165.         // initialize our class variables
  166.             fCurDoc = nil;
  167.             fDone = false;
  168.             fInBackground = false;
  169.             fMouseRgn = nil;
  170.             fWhichWindow = nil;
  171.             
  172.     } /* TApplication (constructor) */
  173.  
  174.  
  175. //-----------------------------------------------------------------------
  176. // TApplication::ExitLoop -     we're quitting the application; let's
  177. //                                do whatever needs to be done to clean up.
  178. //                                In our case, there isn't much to be done.
  179. //
  180.     void TApplication::ExitLoop( void )
  181.     {
  182.         fDone = true;
  183.     }
  184.  
  185.  
  186. //-----------------------------------------------------------------------
  187. // TApplication::EventLoop -     keep track of events and handle them
  188. //                                appropriately.
  189. //
  190.     void TApplication::EventLoop( void )
  191.     {
  192.         int gotEvent;
  193.         EventRecord tEvt;
  194.     
  195.         SetUp();                    // call setup routine
  196.         DoIdle();                    // do idle once
  197.     
  198.         while (fDone == false)
  199.           {
  200.             // always set up fWhichWindow before doing anything
  201.                 fWhichWindow = FrontWindow();
  202.                 
  203.             // see if window belongs to a document
  204.                 fCurDoc = fDocList->FindDoc(fWhichWindow);
  205.                 
  206.             // make sure we always draw into correct window
  207.                 SetPort(fWhichWindow);
  208.     
  209.             // let's allow others to use the cpu if they need (Multifinder friendliness).
  210.                 DoIdle();            // call idle time handler. this lets apps blink the caret
  211.                                     // or whatever else they wish to do
  212.             
  213.             //     determine if an event has occurred and what to do about it
  214.                 if ( fHaveWaitNextEvent )
  215.                 {
  216.                     gotEvent = WaitNextEvent( everyEvent, &tEvt, SleepVal(), fMouseRgn );
  217.                 }
  218.                 else
  219.                 {
  220.                     SystemTask();
  221.                     gotEvent = GetNextEvent( everyEvent, &tEvt );
  222.                 }
  223.                 fTheEvent = tEvt;
  224.     
  225.             // make sure we got a real event
  226.                 if ( gotEvent )
  227.                 {
  228.                     AdjustCursor();
  229.                     switch (fTheEvent.what)
  230.                     {
  231.                         case mouseDown :    DoMouseDown();
  232.                                             break;
  233.                                             
  234.                         case mouseUp :        DoMouseUp();
  235.                                             break;
  236.                                             
  237.                         case keyDown :
  238.                         case autoKey :        DoKeyDown();
  239.                                             break;
  240.                                             
  241.                         case updateEvt :    DoUpdateEvt();                
  242.                                             break;
  243.                                             
  244.                         case diskEvt :        DoDiskEvt();
  245.                                             break;
  246.                                             
  247.                         case activateEvt :    DoActivateEvt();
  248.                                             break;
  249.                                             
  250.                         case kOsEvent :        DoOSEvent();
  251.                                             break;
  252.                                             
  253.                         default :            break;
  254.                         
  255.                     } // end switch (fTheEvent.what)
  256.                 }
  257.                 
  258.             // update the cursor shape as needed after the event
  259.                 AdjustCursor();
  260.         }
  261.         // call cleanup handler
  262.         CleanUp();
  263.         
  264.     }  /* TApplication::EventLoop */
  265.  
  266.  
  267. //-----------------------------------------------------------------------
  268. // TApplication::DoKeyDown -     simple routine to handle key presses.
  269. //
  270.     void TApplication::DoKeyDown( void )
  271.     {
  272.         char key;
  273.         long mResult;
  274.     
  275.         key = (char) ( fTheEvent.message & charCodeMask );
  276.         if (( fTheEvent.modifiers & cmdKey ) && ( fTheEvent.what == keyDown ))
  277.         {
  278.             // only do command keys if we are not autokeying
  279.                 AdjustMenus();                    // make sure menus are up to date
  280.                 mResult = MenuKey( key );
  281.                 if ( mResult != 0 )                // if it wasn't a menu key, pass it through
  282.                 {
  283.                     DoMenuCommand( HiWrd( mResult ), LoWrd( mResult ));
  284.                     return;
  285.                 }
  286.         }
  287.         
  288.         if ( fCurDoc != nil )
  289.         {
  290.             EventRecord tEvt;
  291.     
  292.             // we copy event record so that we don't pass reference to object field 
  293.             tEvt = fTheEvent;
  294.             fCurDoc->DoKeyDown( &tEvt );
  295.         }
  296.           
  297.     }  /* TApplication::DoKeyDown */
  298.  
  299.  
  300. //-----------------------------------------------------------------------
  301. // TApplication::DoActivateEvt -     a window is becoming active. if it is
  302. //                                    one of ours, call the document's activate
  303. //                                    routine.
  304. //
  305.     void TApplication::DoActivateEvt( void )
  306.     {
  307.         // event record contains window ptr
  308.             fWhichWindow = (WindowPtr) fTheEvent.message;
  309.  
  310.         // see if window belongs to a document
  311.             fCurDoc = fDocList->FindDoc( fWhichWindow );
  312.             SetPort( fWhichWindow );
  313.     
  314.         if ( fCurDoc != nil )
  315.           fCurDoc->DoActivate(( fTheEvent.modifiers & activeFlag ) != 0 );
  316.     
  317.     }  /* TApplication::DoActivateEvt */
  318.  
  319.  
  320. //-----------------------------------------------------------------------
  321. // TApplication::DoUpdateEvt -     a window needs to be updated. If it is one
  322. //                                of ours, call the document's update routine
  323. //                                to redraw it.
  324. //
  325.     void TApplication::DoUpdateEvt(void)
  326.     {
  327.         // event record contains window ptr
  328.             fWhichWindow = (WindowPtr) fTheEvent.message;
  329.  
  330.         // see if window belongs to a document
  331.             fCurDoc = fDocList->FindDoc( fWhichWindow );
  332.             SetPort( fWhichWindow );
  333.         
  334.             if ( fCurDoc != nil )
  335.                 fCurDoc->DoUpdate();
  336.           
  337.     }  /* TApplication::DoUpdateEvt */
  338.  
  339.  
  340. //-----------------------------------------------------------------------
  341. // TApplication::DoSuspend -     although our suspend and resume routine are
  342. //                                identical, let's use two distinct routines
  343. //                                so that a subclass can choose to override one
  344. //                                without having to rewrite the other.
  345. //
  346.     void TApplication::DoSuspend( Boolean doClipConvert )
  347.     {
  348.         doClipConvert = false;        // this is here because I HATE compiler warnings!!
  349.         if (fCurDoc != nil)
  350.           fCurDoc->DoActivate( !fInBackground );
  351.           
  352.     }  /* TApplication::DoSuspend */
  353.  
  354.  
  355. //-----------------------------------------------------------------------
  356. // TApplication::DoResume -     although our suspend and resume routine are
  357. //                                identical, let's use two distinct routines
  358. //                                so that a subclass can choose to override one
  359. //                                without having to rewrite the other.
  360. //
  361.     void TApplication::DoResume( Boolean doClipConvert )
  362.     {
  363.         doClipConvert = false;        // this is here because I HATE compiler warnings!!
  364.         if ( fCurDoc != nil )
  365.           fCurDoc->DoActivate( !fInBackground );
  366.           
  367.     }  /* TApplication::DoResume */
  368.  
  369.  
  370. //-----------------------------------------------------------------------
  371. // TApplication::DoOSEvent -     handle multifinder events accordingly.
  372. //
  373.     void TApplication::DoOSEvent(void)
  374.     {
  375.         Boolean doConvert;
  376.         unsigned char evType;
  377.     
  378.         // is it a multifinder event?
  379.             evType = (unsigned char) (fTheEvent.message >> 24) & 0x00ff;
  380.             switch ( evType )                    // high byte of message is type of event
  381.             {                                     
  382.                 case kMouseMovedMessage :        DoIdle();                    // mouse-moved is also an idle event
  383.                                                 break;
  384.                     
  385.                 case kSuspendResumeMessage :    doConvert = ( fTheEvent.message & kClipConvertMask ) != 0;
  386.                                                 fInBackground = ( fTheEvent.message & kResumeMask ) == 0;
  387.                                                 
  388.                                                 // depending on whether or not we're in the background call suspend or resume
  389.                                                     if ( fInBackground )
  390.                                                         DoSuspend( doConvert );
  391.                                                     else
  392.                                                         DoResume( doConvert );
  393.                                                 
  394.                                                 break;
  395.             }
  396.         
  397.     }  /* TApplication::DoOSEvent */
  398.  
  399.  
  400. //-----------------------------------------------------------------------
  401. // TApplication::DoMouseDown -     simple routine to handle a mouse click.
  402. //
  403.     void TApplication::DoMouseDown( void )
  404.     {
  405.         long        mResult;
  406.         short        partCode;
  407.         WindowPtr    tWind;
  408.         EventRecord    tEvt;
  409.     
  410.         // gotta watch those object field dereferences
  411.             partCode = FindWindow( fTheEvent.where, &tWind );
  412.             fWhichWindow = tWind;
  413.             tEvt = fTheEvent;
  414.             switch ( partCode )
  415.             {
  416.                 case inSysWindow :    DoMouseInSysWindow();
  417.                                     break;
  418.                                     
  419.                 case inMenuBar :    AdjustMenus();
  420.                                     mResult = MenuSelect( tEvt.where );
  421.                                     if ( mResult != 0 )
  422.                                       DoMenuCommand(HiWrd( mResult ), LoWrd( mResult ));
  423.                                     break;
  424.                                     
  425.                 case inGoAway :        DoGoAway();                    
  426.                                     break;
  427.                                     
  428.                 case inDrag :        DoDrag();
  429.                                     break;
  430.                                     
  431.                 case inGrow :        if ( fCurDoc != nil )
  432.                                           fCurDoc->DoGrow( &tEvt );                    
  433.                                     break;
  434.                 case inZoomIn :
  435.                 case inZoomOut :    if (( TrackBox(fWhichWindow, tEvt.where, partCode )) && ( fCurDoc != nil ))
  436.                                         fCurDoc->DoZoom(partCode);
  437.                                     break;
  438.                                     
  439.                 case inContent :    // If window is not in front, make it so
  440.                                         if ( fWhichWindow != FrontWindow() )
  441.                                             SelectWindow(fWhichWindow);
  442.                                         else
  443.                                             if (fCurDoc != nil)
  444.                                                  fCurDoc->DoContent(&tEvt);                    
  445.                                     break;
  446.             }
  447.           
  448.     }  /* TApplication::DoMouseDown */
  449.  
  450.  
  451. //-----------------------------------------------------------------------
  452. // TApplication::DoDrag -     have the system track the mouse movements and
  453. //                            drag the window accordingly.
  454. //
  455.     void TApplication::DoDrag( void )
  456.     {
  457.         DragWindow( fWhichWindow, fTheEvent.where, &qd.screenBits.bounds );
  458.         
  459.     }  /* TApplication::DoDrag */
  460.  
  461.  
  462. //-----------------------------------------------------------------------
  463. // TApplication::DoGoAway -     a mousedown event occurred in the go away region
  464. //                                of the active window; continue tracking it. If
  465. //                                the mouse is released in the region, then close
  466. //                                the window.
  467. //
  468.     void TApplication::DoGoAway( void )
  469.     {
  470.         if ( TrackGoAway( fWhichWindow, fTheEvent.where ))            // was the mouse released in the goAway region?
  471.         {                                                            // yes, but is the window ours?
  472.             if ( fCurDoc != nil )
  473.             {                                                        // it is our window, let's close it
  474.                 fDocList->RemoveDoc( fCurDoc );
  475.                 fCurDoc->DoClose();
  476.             }
  477.             else                                                    // no, the window must belong to the system, let them handle it
  478.                 CloseDeskAcc(((WindowPeek) fWhichWindow )->windowKind );
  479.                 
  480.             // make sure our current document/window references are valid
  481.                 if ( fWhichWindow != nil )                            // does an active window remain? 
  482.                 {
  483.                     fCurDoc = fDocList->FindDoc( fWhichWindow );    // yes, update the current document pointer
  484.                     SetPort( fWhichWindow );                        // be sure to make future drawings to the new window
  485.                 }
  486.                 else
  487.                     fCurDoc = nil;                                    // no active window remains
  488.         }
  489.     }  /* TApplication::DoGoAway */
  490.  
  491.  
  492. //-----------------------------------------------------------------------
  493. // TApplication::TrapAvailable -     Check and see if the trap exists. 
  494. //
  495.     Boolean TApplication::TrapAvailable(short tNumber,TrapType tType)
  496.     {
  497.         // On 64K ROM machines, tType will be ignored.
  498.             return NGetTrapAddress( tNumber, tType ) != NGetTrapAddress( _Unimplemented, ToolTrap);
  499.         
  500.     }  /* TApplication::TrapAvailable */
  501.  
  502.  
  503. //-----------------------------------------------------------------------
  504. // TApplication::AlertUser -     Simple routine to display an alert dialog
  505. //                                using str# resources. Although this routine
  506. //                                exists and is used in this sample, a more
  507. //                                streamlined approach would be to create a
  508. //                                dialog library (or even an object) which
  509. //                                could be linked in. Using such a method,only
  510. //                                one source copy would exist.
  511. //
  512.     void TApplication::AlertUser( short errResID, short errCode )
  513.     {
  514.         Str255 message;
  515.     
  516.         SetCursor( &qd.arrow );
  517.         GetIndString( message, errResID, errCode );
  518.         ParamText(message, (ConstStr255Param) "\p", (ConstStr255Param) "\p", (ConstStr255Param) "\p" );
  519.         (void) Alert( rUserAlert, nil);
  520.         
  521.     }  /* TApplication::AlertUser */
  522.  
  523. //-----------------------------------------------------------------------
  524. // TApplication::BigBadError -     A variation of AlertUser which aborts to
  525. //                                the finder. 
  526. //
  527.     void TApplication::BigBadError(short errResID, short errCode)
  528.     {
  529.         AlertUser( errResID,errCode );
  530.         ExitToShell();
  531.         
  532.     }  /* TApplication::BigBadError */
  533.     
  534. // That's all, folks...
  535.